package com.manning.readinglist;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;

/**
 * 覆盖自动配置的显式安全配置。
 * SecurityConfig 是个非常基础的 Spring Security 配置，尽管如此，它还是完成了不少安全定制工作。通过这个自定义的安全配置类，我们让 Spring Boot 跳过了安全自动配置，转而使用我们
 * 的安全配置。扩展了 WebSecurityConfigurerAdapter 的配置类可以覆盖两个不同的 configure() 方法。
 */
// 假设 SecurityConfig 里创建的安全配置是针对生产环境的，而自动配置的安全配置用在开发环境刚刚好。我们就能为 SecurityConfig 加上 @Profile 注解。
// 这里用的 @Profile 注解要求运行时激活 production Profile，这样才能应用该配置。如果 production Profile 没有激活，就会忽略该配置，而此时缺少其他用于覆盖的安全配置，于是应
// 用自动配置的安全配置。
@Profile("production")
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private ReaderRepository readerRepository;

    /**
     * 在 SecurityConfig 里，第一个 configure() 方法指明，“/”（ReadingListController 的方法映射到了该路径）的请求只有经过身份认证且拥有 READER 角色的用户才能访问。其他的
     * 所有请求路径向所有用户开放了访问权限。这里还将登录页和登录失败页（带有一个 error 属性）指定到了 /login。
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/").access("hasRole('READER')")   // 要求登录者有 READER 角色
                .antMatchers("/**").permitAll()
                .and()
                .formLogin()
                .loginPage("/login")    // 设置登录表单的路径
                .failureUrl("/login?error=true");
    }

    /**
     * 第二个 configure() 方法设置了一个自定义的 UserDetailsService，这个服务可以是任意实现了 UserDetailsService 的类，用于查找指定用户名的用户。提供了一个匿名内部类实现，
     * 简单地调用了注入 ReaderRepository（这是一个 Spring Data JPA 仓库接口）的 findOne() 方法。
     * @param auth
     * @throws Exception
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//        auth.userDetailsService(new UserDetailsService() {  // 定义自定义 UserDetailsService
//            @Override
//            public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
//                return readerRepository.findOne(username);
//            }
//        });
    }
}
